#include "stm8s.h"
#include "system.h"
#include "ril.h"
int8_t next_token(void);
int8_t reapipv4(uint8_t* ipbuf);
uint8_t isDecChar(uint8_t ch);
int8_t reaport(uint8_t* pobuf);
#define AT_LEN 7
#define CPINQ_LEN 29
#define CSQ_LEN 9
#define CGREGQ_LEN 50
#define QIMODE_LEN 14
#define QICSGP_LEN 22
#define QICSGPQ_LEN 13
#define QIREGAPP_LEN 14
#define QIACT_LEN 11
//#define QILOCIP_LEN 13
#define CIMI_LEN 10
#define ATV1_LEN 7
#define QIHEAD_LEN 14
#define QIDNSIP_LEN 15
#define QIOPEN_LEN 60
#define QISEND_LEN 18
#define MQTT_CONNECT_LEN 43
#define MQTT_PUBLISH_LEN 98+15
#define MQTT_DISCONN_LEN 11
#define QIOPEN_CLOSE 13
#define QIFGCNT_LEN 17
#define QGNSSTSQ_LEN 31
#define QGNSSEPO_LEN 18
#define QGNSSC_LEN 16
#define QGNSSRD_LEN 33
#define QCFG_LEN 28
#define CPMS_LEN 21
#define CMGF_LEN 14
#define CSDH_LEN 14
#define CSCS_LEN 18
#define CMGR_LEN 19
#define CMGD_LEN 16
const uint8_t at_atry[AT_LEN]={'A','T',0x0D,0x0D,0x0A,'O','K'};
const uint8_t at_cpinQ[CPINQ_LEN]={'A','T','+','C','P','I','N','?',0x0D,0x0D,0x0A,'+','C','P','I','N',':',' ','R','E','A','D','Y',0x0D,0x0A,0x0D,0x0A,'O','K'};
const uint8_t at_csq[CSQ_LEN]={'A','T','+','C','S','Q',0x0D,0x0D,0x0A};
const uint8_t at_cgregQ[CGREGQ_LEN]={'A','T','+','C','R','E','G','?',';','+','C','G','R','E','G','?',0x0D,0x0D,0x0A,'+','C','R','E','G',':',' ','0',',','1',0x0D,0x0A,0x0D,0x0A,'+','C','G','R','E','G',':',' ','0',',','1',0x0D,0x0A,0x0D,0x0A,'O','K'};
const uint8_t at_qimode[QIMODE_LEN]={'A','T','+','Q','I','M','O','D','E','=','0',0x0D,0x0D,0x0A};
const uint8_t at_qicsgp[QICSGP_LEN]={'A','T','+','Q','I','C','S','G','P','=','1',',','"','C','M','N','E','T','"',0x0D,0x0D,0x0A};
const uint8_t at_qicsgpQ[QICSGPQ_LEN]={'A','T','+','Q','I','C','S','G','P','?',0x0D,0x0D,0x0A};
const uint8_t at_qiregapp[QIREGAPP_LEN]={'A','T','+','Q','I','R','E','G','A','P','P',0x0D,0x0D,0x0A};

const uint8_t at_qiact[QIACT_LEN]={'A','T','+','Q','I','A','C','T',0x0D,0x0D,0x0A};
//const uint8_t at_qilocip[QILOCIP_LEN]={'A','T','+','Q','I','L','O','C','I','P',0x0D,0x0D,0x0A};
const uint8_t at_cimi[CIMI_LEN]={'A','T','+','C','I','M','I',0x0D,0x0D,0x0A};
const uint8_t at_atv1[ATV1_LEN]={'A','T','V','1',0x0D,0x0D,0x0A};
const uint8_t at_qihead[QIHEAD_LEN]={'A','T','+','Q','I','H','E','A','D','=','0',0x0D,0x0D,0x0A};
const uint8_t at_qidnsip[QIDNSIP_LEN]={'A','T','+','Q','I','D','N','S','I','P','=','0',0x0D,0x0D,0x0A};
const uint8_t at_qiopen[QIOPEN_LEN]={'A','T','+','Q','I','O','P','E','N','=','"','T','C','P','"',',','"','0','4','7','.','0','9','4','.','1','4','9','.','1','8','2','"',',','"','0','1','8','8','3','"',0x0D,0x0D,0x0A,'O','K',0x0D,0x0A,0x0D,0x0A,'C','O','N','N','E','C','T',' ','O','K'};
#define IPS0L   at_qiopen[17]
#define IPS0M   at_qiopen[18]
#define IPS0R   at_qiopen[19]
#define IPS1L   at_qiopen[21]
#define IPS1M   at_qiopen[22]
#define IPS1R   at_qiopen[23]
#define IPS2L   at_qiopen[25]
#define IPS2M   at_qiopen[26]
#define IPS2R   at_qiopen[27]
#define IPS3L   at_qiopen[29]
#define IPS3M   at_qiopen[30]
#define IPS3R   at_qiopen[31]
//#define PORT4   at_qiopen[35]
#define PORT3   at_qiopen[36]
#define PORT2   at_qiopen[37]
#define PORT1   at_qiopen[38]
#define PORT0   at_qiopen[39]
 uint8_t at_qisend[QISEND_LEN]={'A','T','+','Q','I','S','E','N','D','=','0','0','0',0x0D,0x0D,0x0A,'>',' '};
 uint8_t mqtt_connect[MQTT_CONNECT_LEN]={0x10, 0x20, 0x00, 0x04, 0x4d, 0x51, 0x54, 0x54, 0x04, 0x02, 0x00, 0x06, 0x00, 0x14, 'U', 's', 'e', 'r', 'I', 'D', ':', '0','1','2','3','4','5','6','7','#','#','#','#','#', 0x0D,0x0A,'S','E','N','D',' ','O','K'};
const uint8_t mqtt_connack[4]={0x20,0x02,0x00,0x00};
 uint8_t mqtt_publish[MQTT_PUBLISH_LEN]={0x32, 0x66, 0x00, 0x12, VENDOR_ID_F,VENDOR_ID_B,'/','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5', 0x55, 0xAA, '<','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@', 'G', 'O', '>', 0x0D,0x0A,'S','E','N','D',' ','O','K'};
const uint8_t mqtt_puback[4]={0x40,0x02,0x55,0xAA};
const uint8_t mqtt_disconnect[MQTT_DISCONN_LEN]={0xE0,0x00,0x0D,0x0A,'S','E','N','D',' ','O','K'};
const uint8_t at_qiclose[QIOPEN_CLOSE]={'A','T','+','Q','I','C','L','O','S','E',0x0D,0x0D,0x0A};
 uint8_t at_qifgcnt[QIFGCNT_LEN]={'A','T','+','Q','I','F','G','C','N','T','=',' ',0x0D,0x0D,0x0A,'O','K'};
const uint8_t at_qgnsstsq[QGNSSTSQ_LEN]={'A','T','+','Q','G','N','S','S','T','S','?',0x0D,0x0D,0x0A,'+','Q','G','N','S','S','T','S',':',' ','1',0x0D,0x0A,0x0D,0x0A,'O','K'};
 uint8_t at_qgnssepo[QGNSSEPO_LEN]={'A','T','+','Q','G','N','S','S','E','P','O','=','1',0x0D,0x0D,0x0A,'O','K'};
 uint8_t at_qgnssc[QGNSSC_LEN]={'A','T','+','Q','G','N','S','S','C','=',' ',0x0D,0x0D,0x0A,'O','K'};
const uint8_t at_qgnssrd[QGNSSRD_LEN]={'A','T','+','Q','G','N','S','S','R','D','=','"','N','M','E','A','/','R','M','C','"',0x0D,0x0D,0x0A,'+','Q','G','N','S','S','R','D',':'};
const uint8_t at_qcfg[QCFG_LEN]={'A','T','+','Q','C','F','G','=','"','U','R','C','/','D','i','s','a','b','l','e','"',',','1',0x0D,0x0D,0x0A,'O','K'};
const uint8_t at_cpms[CPMS_LEN]={'A','T','+','C','P','M','S','=','"','S','M','"',0x0D,0x0D,0x0A,'+','C','P','M','S',':'};
const uint8_t at_cmgf[CMGF_LEN]={'A','T','+','C','M','G','F','=','1',0x0D,0x0D,0x0A,'O','K'}; //use text mode
const uint8_t at_csdh[CSDH_LEN]={'A','T','+','C','S','D','H','=','0',0x0D,0x0D,0x0A,'O','K'}; //Don't show header values in text mode
const uint8_t at_cscs[CSCS_LEN]={'A','T','+','C','S','C','S','=','"','G','S','M','"',0x0D,0x0D,0x0A,'O','K'};
 uint8_t at_cmgr[CMGR_LEN]={'A','T','+','C','M','G','R','=','0','0',0x0D,0x0D,0x0A,'+','C','M','G','R',':'};
const uint8_t at_cmgd[CMGD_LEN]={'A','T','+','C','M','G','D','=','1',',','4',0x0D,0x0D,0x0A,'O','K'};
const uint8_t d1s = 4;
const uint8_t d2s = 8;
const uint8_t d3s = 12;
const uint8_t d5s = 20;
const uint8_t SyncPeriod = 1;
//AT+QIOPEN="TCP","47.94.149.182","1883"
//AT+QISEND=21
//10 13 00 04 4d 51 54 54 04 02 00 1e 00 07 75 73 65 72 20 69 64
//AT+QISEND=28
//32 1a 00 03 70 6f 73 00 01 63 76 6f 20 2b 20 63 61 72 20 2b 20 68 6f 75 73 65 21 21
uint8_t isx;
uint8_t isxsav;
uint8_t executelist[]={EXID_WAIT_LS, //0

                       ATID_CSQ,
                       EXID_EJPF, //2
                           
                       ATID_CPINQ,
                       EXID_EJPB, //4 to main top
                       EXID_WAIT_MS, //5
                       
                       ATID_CGREGQ,
                       EXID_EJPB, //7 to main top

                       EXID_CALL_GNSS, //8
                       
                       ATID_QICSGPQ,
                       EXID_WAIT_MS, //10
                           
                       ATID_QIOPEN,
                       EXID_WAIT_MS_EJP, //12
                           
                       ATID_QISEND,
                       EXID_WAIT_MS, //14
                           
                       EXID_DATA_CON,
                       EXID_GET_CONACK, //16
                       EXID_WAIT_MS_EJP, //17
                       
                       ATID_QISEND,
                       EXID_WAIT_MS, //19
                           
                       EXID_DATA_PUB,
                       EXID_GET_PUBACK, //21
                       EXID_WAIT_MS_EJP, //22
                       
                       ATID_QISEND, //23
                       EXID_DATA_DISCON, //24
                       ATID_CLOSE, //inet close
                       
                       EXID_CALL_REMOTE_CMD, //26
                       EXID_JPB, //main loop bottom
                       
                       EXID_WAIT_MS, //launch point
                       EXID_POWER_ON,
                       EXID_WAIT_MS,
                       ATID_ATRY,
                       ATID_ATRY,
                       ATID_ATRY,
                       EXID_EJPB, //error then back to launch point
                       
                       EXID_TEST, //ATID_ATV1,
                       EXID_WAIT_MS, //-22
                       
                       ATID_QCFG,
                       EXID_WAIT_MS, //-20
                       
                       ATID_CPINQ,
                       EXID_WAIT_MS_EJP, //-18

                       ATID_CGREGQ,
                       EXID_WAIT_MS, //-16
                       
                       ATID_QIMODE,
                       EXID_WAIT_MS, //-14

                       ATID_QICSGP,
                       EXID_WAIT_MS, //-12

                       ATID_QIREGAPP,
                       EXID_WAIT_MS, //-10
                       
                       ATID_QIACT,
                       EXID_WAIT_MS_EJP, //-8
                           
                       ATID_CIMI, //ATID_QILOCIP,
                       EXID_WAIT_MS, //-6
                           
                       ATID_QIHEAD,
                       EXID_WAIT_MS, //-4
                           
                       ATID_QIDNSIP,
                       EXID_WAIT_MS, //-2
                       EXID_JPB}; //-1 to main loop
#define LP (sizeof(executelist)-30)
#define AFLP (sizeof(executelist)-28)
#define INET_CLOSE 25
#define MAIN_LOOP_BOTTOM 27
uint8_t exparamlist[sizeof(executelist)]={0};
uint8_t parambackup[sizeof(executelist)];

uint8_t execsublist[]={EXID_WAIT_MS, //0
                       ATID_QIFGCNT,
                       EXID_WAIT_MS, //2
                       
                       ATID_QICSGP,
                       EXID_WAIT_MS, //4
                       
                       ATID_CGREGQ,
                       EXID_EJPF,    //6
                       
                       ATID_QGNSSTSQ,
                       EXID_EJPF,    //8
                       
                       ATID_QGNSSEPO,
                       EXID_WAIT_MS, //10
                       
                       ATID_QGNSSC,
                       EXID_WAIT_MS, //12
                       
                       ATID_QGNSSRD,
                       EXID_UNTIL_TIMEOUT, //14
                       
                       ATID_QGNSSC,
                       EXID_WAIT_MS, //16
                       
                       ATID_QGNSSEPO,
                       EXID_WAIT_MS, //18
                       
                       ATID_QIFGCNT,
                       
                       EXID_WAIT_MS, //20
                       EXID_RET};

uint8_t subparalist[sizeof(execsublist)-1]={0};
uint8_t subprbackup[sizeof(execsublist)-1];

uint8_t sms_processed_idx=0;
uint8_t sms_current_idx;
uint8_t sms_max_mumber;
uint8_t cpmsresult[8]={0};
uint8_t execsublst2[]={EXID_TRUE_JPF, //0
                        ATID_CPMS,
                        EXID_SMSIDX_EQSKIP,
                        ATID_CMGF,
                        ATID_CSDH,
                        ATID_CSCS,
                        ATID_CMGR,
                        EXID_PARSE,
                        EXID_TEST,
                        EXID_RET};
uint8_t subparalst2[sizeof(execsublst2)-1]={0};
uint8_t subpbackup2[sizeof(execsublst2)-1];

uint8_t tLongTimeBase;  //event 256ms
uint8_t LongTimeCount;
uint8_t onResponse;
uint8_t Matched;
int8_t errno;
uint16_t AtTimeOutCnt;
uint16_t AtTimeOutCntH;
uint8_t* execv;
uint8_t* pvect;
uint8_t* pbvec;
uint8_t iterator;

void SyncPeriodResolutSet()
{
    LongTimeCount = 60;
}

void SyncPeriodSet(uint8_t sv)
{
    exparamlist[0] = sv;
    parambackup[0] = sv;
}

void SetCmdParam(uint8_t indicator, uint8_t delay)
{
    exparamlist[indicator] = delay;
    parambackup[indicator] = delay;
}

void SetSubParam(uint8_t indicator, uint8_t val)
{
    subparalist[indicator] = val;
    subprbackup[indicator] = val;
}

void SetWaitMsParam(uint8_t indicator)
{
    pvect[indicator] = pbvec[indicator];
}

void ModemPowerOnDelaySet()
{
     exparamlist[sizeof(executelist)-29] = 5; //1 ~ 1.25 sec low-level launch action
}

void rilinit()
{
    //errno = 0;
    execv = executelist;
    pvect = exparamlist;
    pbvec = parambackup;
    onResponse = FALSE; //send state
    isx = sizeof(executelist)-30; //launch point
    SyncPeriodResolutSet();
    
    //mainlist
    //SyncPeriodSet((uint8_t)SyncPeriod); why not ??
    //SyncPeriodSet(FLASH_ReadByte((uint32_t)&SyncPeriod));
    exparamlist[0] = SyncPeriod;
    parambackup[0] = SyncPeriod;
    SetCmdParam(2,LP); //critical error then go to launch point
    SetCmdParam(3,4); //ATID_CPINQ timeout 5 times base
    SetCmdParam(4,0); //no sim then to main top
    SetCmdParam(5,2);
    SetCmdParam(6,3); //ATID_CREG timeout 4 times base
    SetCmdParam(7,0); //register network fail then to main top
    SetCmdParam(10,2);
    SetCmdParam(11,15); //open timeout 16 times base
    exparamlist[12] = d2s; //open success then delay 2 secs
    parambackup[12] = MAIN_LOOP_BOTTOM-1; //open fail then back to mainloop
    SetCmdParam(13,MQTT_CONNECT_LEN-9); // send=N
    SetCmdParam(14,2);
    SetCmdParam(15,19); //connect data timeout 20 times base
    SetCmdParam(16,15);  //connack timeout 16 times base
    
    exparamlist[17] = d1s; //~1s
    parambackup[17] = INET_CLOSE; //to close
    SetCmdParam(18,MQTT_PUBLISH_LEN-9); // send=N
    SetCmdParam(19,2);
    SetCmdParam(20,19); //publish data timeout 20 times base
    SetCmdParam(21,15);  //puback timeout 16 times base
    exparamlist[22] = d1s; //~1s
    parambackup[22] = 17;
    SetCmdParam(23,MQTT_DISCONN_LEN-9); // send=2
    SetCmdParam(MAIN_LOOP_BOTTOM,0);  //mainloop jmp back
    
    SetCmdParam(LP,20); //launch point, 5sec delay before launch modem
    ModemPowerOnDelaySet();
    SetCmdParam(sizeof(executelist)-28,40); //10 sec after launch modem
    SetCmdParam(sizeof(executelist)-24,LP); //error then back to launch point
    SetCmdParam(sizeof(executelist)-22,2);
    SetCmdParam(sizeof(executelist)-20,2);
    exparamlist[sizeof(executelist)-18] = d5s; //wait 5 secs before CREG;CGREG
    parambackup[sizeof(executelist)-18] = AFLP; //After launchpoint
    SetCmdParam(sizeof(executelist)-17,1); //first CREG;CGREG 2 times base
    SetCmdParam(sizeof(executelist)-16,2);
    SetCmdParam(sizeof(executelist)-14,2);
    SetCmdParam(sizeof(executelist)-12,2);
    SetCmdParam(sizeof(executelist)-10,2);
    SetCmdParam(sizeof(executelist)-9,29); //QIACT timeout 30 times base
    exparamlist[sizeof(executelist)-8] = d1s; //QIACT ~1s
    parambackup[sizeof(executelist)-8] = AFLP; //After launchpoint
    
    SetCmdParam(sizeof(executelist)-6,2);
    SetCmdParam(sizeof(executelist)-4,2);
    SetCmdParam(sizeof(executelist)-2,2);
    SetCmdParam(sizeof(executelist)-1,1); //back to main start
    
    //sublist
    SetSubParam(0,4);
    SetSubParam(1,0x20); //set PDP Context = 2
    SetSubParam(2,2);
    SetSubParam(4,2);
    SetSubParam(6,sizeof(execsublist)-2); //register network fail then return
    SetSubParam(7,6); //QGNSSTS? timeout 7 times base
    SetSubParam(8,sizeof(execsublist)-2); //Time sync fail then return
    SetSubParam(9,0x10); //set EPO=1
    SetSubParam(10,8); //after EPO
    SetSubParam(11,0x10); //set GNSSC=1
    SetSubParam(12,24); //after GNSSC=1,keep 6s bfore GNSSRD
    SetSubParam(14,0x25); //back to cur-2, iter 5 times, equal 30sec timeout
    SetSubParam(15,0x00); //set GNSSC=0
    SetSubParam(16,8);
    SetSubParam(17,0x00); //set EPO=0
    SetSubParam(18,2);
    SetSubParam(sizeof(execsublist)-3,0); //set PDP Context = 0
    SetSubParam(sizeof(execsublist)-2,3);
    
    iterator = REMOTE_CHECK_FREQ_DIV;
    //sublist2
    subparalst2[0] = sizeof(execsublst2)-1;
    subparalst2[1] = 1; //cpms timeout 2 times base
    subparalst2[2] = sizeof(execsublst2)-1;
}

void next()
{
    ++isx;
}
void dojmp()
{
    isx = pvect[isx];
}
uint8_t getparam()
{
    return exparamlist[isx];
}
int8_t getRespState()
{
    return onResponse;
}

uint8_t* hdcmp;
uint8_t mvcmp;
uint8_t incmp;
uint8_t mxcmp;
uint8_t datcnt;
uint8_t* dptr;
uint8_t datmax;
uint8_t dstart;
void (*echostore)(uint8_t)=FALSE;
//position info recv
void echostore1(uint8_t dat)
{
    if(0x0D == dat){
        while(datcnt < datmax)
        {
            dptr[dstart+datcnt] = '%';
            ++datcnt;
        }
        echostore = FALSE;
    }else{
        if(datcnt < datmax){
            dptr[dstart+datcnt] = dat;
            ++datcnt;
        }
    }
}
//sms content recv
uint8_t eof;
uint8_t meta,meta_type,meta_sms_step;
uint8_t ctnt;
uint8_t sms_content[SMS_TXT_BUF_LIMIT]; //*HX&DOMAIN&101.200.225.118&9999&16800020400#
uint8_t sms_unread;

void echosub(uint8_t dat)
{
            if(meta){
                if(1 == meta_type){
                    switch(meta_sms_step)
                    {
                    case 0:if('R' == dat){++meta_sms_step;}else{meta=FALSE;meta_sms_step=0;}break;
                    case 1:if('E' == dat){++meta_sms_step;}else{meta=FALSE;meta_sms_step=0;}break;
                    case 2:if('C' == dat){++meta_sms_step;}else{meta=FALSE;meta_sms_step=0;}break;
                    case 3:if(' ' == dat){++meta_sms_step;}else{meta=FALSE;meta_sms_step=0;}break;
                    case 4:
                        if('R' == dat){
                                ++meta_sms_step;
                                sms_unread = FALSE;
                        }else if('U' == dat){
                                ++meta_sms_step;
                                sms_unread = TRUE;
                        }
                    default:if('"' == dat){meta=FALSE;meta_sms_step=0;++meta_type;}
                    }
                }else if(meta_type >= 2){
                    if('"' == dat){
                        meta=FALSE;
                        ++meta_type;
                    }
                }
            }else if(ctnt){
                if(datcnt < datmax){
                    dptr[datcnt++] = dat;
                    if('#' == dat){
                        while(datcnt < datmax){
                            dptr[datcnt++] = dat;
                        }
                        ctnt=FALSE;
                    }
                }else{ctnt=FALSE;}
            }else{
                if('"' == dat){
                    meta = TRUE;
                }else if('*' == dat){
                    ctnt = TRUE;
                }
            }
}

void echostore2(uint8_t dat)
{
    if(0 == eof){
        if(0x0D == dat){
            ++eof;
        }else{
            echosub(dat);
        }
    }else if(1 == eof){
        if(0x0A == dat){
            ++eof;
        }else{
            eof = 0;
        }
    }else if(2 == eof){
        if('O' == dat){
            ++eof;
        }else if(0x0D == dat){
            eof = 1;
        }else{
            eof = 0;
            echosub(dat);
        }
    }else if(3 == eof){
        if('K' == dat){
            ++eof;
        }else{
            eof = 0;
        }
    }else{
        echostore = FALSE;
    }
}

void tomatch(uint8_t dat)
{
    if(incmp){
        if(mvcmp < mxcmp)
        {
            if(dat == hdcmp[mvcmp]){
                ++mvcmp;
                if(mvcmp == mxcmp){
                    Matched = TRUE;
                }
            }else{
                mvcmp = 0;
                incmp = FALSE;
            }
        }else{
            if(echostore){
                echostore(dat);
            }
        }
    }else{
        if(dat == hdcmp[mvcmp]){
            incmp = TRUE;
            ++mvcmp;
        }
    }
}

void wait4match()
{
    if(Matched){
        if(FALSE == echostore){
            onResponse = FALSE;
            next();
        }
    }else{
        ++AtTimeOutCnt;
        if(AtTimeOutCnt){
        }else{
            if((0x0F & pvect[isx]) == AtTimeOutCntH){
                send2consoleb('*');
                send2consoleb(0x0D);
                send2consoleb(0x0A);
                onResponse = FALSE;
                errno = -1;
                next();
            }else{
                ++AtTimeOutCntH;
            }
        }
    }
}

void prepare2wait(uint8_t *atcmd, uint8_t maxrsp)
{
    onResponse = TRUE;
    Matched = FALSE;
    hdcmp = atcmd;
    mvcmp = 0;
    AtTimeOutCnt = 0;
    AtTimeOutCntH = 0;
    incmp = FALSE;
    mxcmp = maxrsp;
    errno = 0;
}

void rilExecute(uint8_t *atcmd, uint8_t maxcmd, uint8_t maxrsp)
{
    send2uart_device(atcmd, maxcmd);
    prepare2wait(atcmd, maxrsp);
}

void byte2decs(uint8_t data, uint8_t *hich, uint8_t *loch)
{
    *hich = (data / 10) + 0x30;
    *loch = (data % 10) + 0x30;
}

void byte2decs3c(uint8_t data, uint8_t *hich, uint8_t *mdch, uint8_t *loch)
{
    uint8_t hc=0,mc=0,lc=0;
    while(data >= 100){
        data -= 100;
        ++hc;
    }
    while(data >= 10){
        data -= 10;
        ++mc;
    }
    lc = data;
    *hich = hc + 0x30;
    *mdch = mc + 0x30;
    *loch = lc + 0x30;
}

uint8_t hic;
uint8_t mdc;
uint8_t loc;
void rilExecSendN(uint8_t *atcmd, uint8_t maxcmd, uint8_t maxrsp)
{
    byte2decs3c(getparam(), &hic, &mdc, &loc);
    atcmd[10] = hic;
    atcmd[11] = mdc;
    atcmd[12] = loc;
    send2uart_device(atcmd, maxcmd);
    prepare2wait(atcmd, maxrsp);
}
void rilExecIndexRead(uint8_t idx, uint8_t offset, uint8_t *atcmd, uint8_t maxcmd, uint8_t maxrsp)
{
    byte2decs(idx, &hic, &loc);
    atcmd[offset] = hic;
    atcmd[offset+1] = loc;
    send2uart_device(atcmd, maxcmd);
    prepare2wait(atcmd, maxrsp);
}

void rilSendData(uint8_t *data, uint8_t maxdat, uint8_t maxrsp)
{
    send2uart_device(data, maxdat);
    prepare2wait(data, maxrsp);
}

void wait_mid_sec()
{
    if(tLongTimeBase){
        tLongTimeBase = 0;
        if(pvect[isx]){
            pvect[isx] -= 1;
        }else{
            SetWaitMsParam(isx);
            next();
            GPIO_WriteReverse(LED_GPIO_PORT, (GPIO_Pin_TypeDef)LED_GPIO_PINS);
        }
    }
}
/* process async sms event <+CMTI: "SM",NN>, save NN to (IndexHiChar,IndexLoChar)
uint8_t IndexHiChar;
uint8_t IndexLoChar;
const uint8_t async_sms_resp[]={'C','M','T','I',':',' ','"','S','M','"',','};
uint8_t area=FALSE; //async response event arrived
uint8_t amch=FALSE;
const uint8_t *asrptr;
uint8_t asrcnt;

void AsyncCmdMatch(uint8_t dat)
{
    if(TRUE == area){
        if(TRUE == amch){
            if(0x0D == dat){
                if(1 == asrcnt){
                    IndexLoChar = IndexHiChar;
                    IndexHiChar = '0';
                }
                area = FALSE; //done
            }else{
                if(asrcnt){
                    IndexLoChar = dat;
                    ++asrcnt;
                }else{
                    IndexHiChar = dat;
                    ++asrcnt;
                }
            }
        }else{
            if(dat == *asrptr++){
                ++asrcnt;
                if(sizeof(async_sms_resp) == asrcnt){
                    amch = TRUE;
                    asrcnt = 0;
                }
            }else{
                area = FALSE;
            }
        }
    }else{
        if('+' == dat){
            area = TRUE;
            amch = FALSE;
            asrptr = async_sms_resp;
            asrcnt = 0;
        }
    }
}
uint8_t charpairs2byte(uint8_t chi, uint8_t clo)
{
    return ((chi - 0x30)*10 + (clo - 0x30));
}*/
uint8_t highchar;
uint8_t lowchar;
uint8_t pgon=FALSE;
uint8_t ips0[3];
uint8_t ips1[3];
uint8_t ips2[3];
uint8_t ips3[3];
uint8_t iport[3];

void rilloop()
{
    uint8_t cmds;

    if(onResponse){
        wait4match();
    }else{
        cmds = execv[isx];
        switch(cmds)
        {
        case ATID_CPINQ:
            rilExecute((uint8_t *)at_cpinQ, CPINQ_LEN-20, CPINQ_LEN);
        break;
        
        case ATID_CSQ:
            rilExecute((uint8_t *)at_csq, CSQ_LEN-2, CSQ_LEN);
        break;
        
        case ATID_CGREGQ:
            rilExecute((uint8_t *)at_cgregQ, CGREGQ_LEN-33, CGREGQ_LEN);
        break;
        
        case ATID_QIMODE:
            rilExecute((uint8_t *)at_qimode, QIMODE_LEN-2, QIMODE_LEN);
        break;
        
        case ATID_QICSGP:
            rilExecute((uint8_t *)at_qicsgp, QICSGP_LEN-2, QICSGP_LEN);
        break;
        
        case ATID_QICSGPQ:
            rilExecute((uint8_t *)at_qicsgpQ, QICSGPQ_LEN-2, QICSGPQ_LEN);
        break;
        
        case ATID_QIREGAPP:
            rilExecute((uint8_t *)at_qiregapp, QIREGAPP_LEN-2, QIREGAPP_LEN);
        break;
        
        case ATID_QIACT:
            rilExecute((uint8_t *)at_qiact, QIACT_LEN-2, QIACT_LEN);
        break;
/*        
        case ATID_QILOCIP:
            rilExecute((uint8_t *)at_qilocip, QILOCIP_LEN-2, QILOCIP_LEN);
        break;
*/      
        case ATID_CIMI:
            echostore = echostore1;
            datcnt = 0;
            
            dptr = mqtt_connect;
            datmax = 15;
            dstart = 18;
            rilExecute((uint8_t *)at_cimi, CIMI_LEN-2, CIMI_LEN);
        break;
        
        case ATID_ATV1:
            rilExecute((uint8_t *)at_atv1, ATV1_LEN-2, ATV1_LEN);
        break;
        
        case ATID_QIHEAD:
            rilExecute((uint8_t *)at_qihead, QIHEAD_LEN-2, QIHEAD_LEN);
            datcnt = 7;
            for(dstart=18; dstart<18+15; dstart++){
                mqtt_publish[datcnt++] = mqtt_connect[dstart];
            }
        break;
        
        case ATID_QIDNSIP:
            rilExecute((uint8_t *)at_qidnsip, QIDNSIP_LEN-2, QIDNSIP_LEN);
        break;
        
        case ATID_QIOPEN:
            rilExecute((uint8_t *)at_qiopen, QIOPEN_LEN-18, QIOPEN_LEN);
        break;
        
        case ATID_QISEND:
            rilExecSendN(at_qisend, QISEND_LEN-4, QISEND_LEN);
        break;
        
        case ATID_ATRY:
            rilExecute((uint8_t *)at_atry, 3, AT_LEN);
        break;
        
        case ATID_CLOSE:
            rilExecute((uint8_t *)at_qiclose, QIOPEN_CLOSE-2, QIOPEN_CLOSE);
        break;
        
        case EXID_EJPF:
            if(errno){
                errno = 0;
                dojmp();
            }else{
                next();
            }
        break;
        
        case EXID_JPB:
            dojmp();
        break;
        
        case EXID_WAIT_MS_EJP:
            if(errno){
                errno = 0;
                isx = parambackup[isx]; //dojmp();
            }else{
                if(tLongTimeBase){
                    tLongTimeBase = 0;
                    if(exparamlist[isx]){
                        exparamlist[isx] -= 1;
                    }else{
                        exparamlist[isx] = d3s;
                        next();
                    }
                }
            }
        break;
        
        case EXID_WAIT_MS:
            wait_mid_sec();
        break;
        
        case EXID_WAIT_LS:
            
            if(tLongTimeBase){
                tLongTimeBase = 0;
                if(LongTimeCount){
                    --LongTimeCount;
                }else{
                    SyncPeriodResolutSet();
                    exparamlist[isx] -= 1;
                    if(0 == exparamlist[isx]){
                        exparamlist[0] = parambackup[0];
                        errno = 0;
                        next();
                    }
                }
            }
        break;
        
        case EXID_POWER_ON:
            if(tLongTimeBase){
                tLongTimeBase = 0;
                GPIO_WriteLow(MC20_GPIO_PORT, (GPIO_Pin_TypeDef)MC20_PWRK_PINS); //launch modem
                if(exparamlist[isx]){
                    exparamlist[isx] -= 1;
                    if(0 == exparamlist[isx]){
                        ModemPowerOnDelaySet();
                        GPIO_WriteHigh(MC20_GPIO_PORT, (GPIO_Pin_TypeDef)MC20_PWRK_PINS); //launch complete
                        errno = 0;
                        next();
                    }
                }
            }
        break;
        
        case EXID_DATA_CON:
            rilSendData(mqtt_connect, MQTT_CONNECT_LEN-9, MQTT_CONNECT_LEN);
        break;
        
        case EXID_DATA_PUB:
            rilSendData(mqtt_publish, MQTT_PUBLISH_LEN-9, MQTT_PUBLISH_LEN);
        break;
        
        case EXID_CALL_GNSS:
            isxsav = isx + 1;
            isx = 0;
            execv = execsublist;
            pvect = subparalist;
            pbvec = subprbackup;
        break;
        
        case ATID_QIFGCNT:
            at_qifgcnt[11] = 0x30 + (subparalist[isx] >> 4);
            rilExecute(at_qifgcnt, QIFGCNT_LEN-4, QIFGCNT_LEN);
        break;
        
        case ATID_QGNSSTSQ:
            rilExecute((uint8_t *)at_qgnsstsq, QGNSSTSQ_LEN-19, QGNSSTSQ_LEN);
        break;

        case ATID_QGNSSEPO:
            at_qgnssepo[12] = 0x30 + (subparalist[isx] >> 4);
            rilExecute(at_qgnssepo, QGNSSEPO_LEN-4, QGNSSEPO_LEN);
        break;

        case ATID_QGNSSC:
            at_qgnssc[10] = 0x30 + (subparalist[isx] >> 4);
            rilExecute(at_qgnssc, QGNSSC_LEN-4, QGNSSC_LEN);
        break;

        case ATID_QGNSSRD:
            echostore = echostore1;
            datcnt = 0;
            
            dptr = mqtt_publish;
            datmax = 74;
            dstart = 25;
            rilExecute((uint8_t *)at_qgnssrd, QGNSSRD_LEN-11, QGNSSRD_LEN);
        break;

        case EXID_UNTIL_TIMEOUT:
            if('A' == mqtt_publish[10+19]){
                next();
            }else{
                if((0x0F & pvect[isx])){
                    --pvect[isx];
                    isx -= (pbvec[isx] >> 4);
                }else{
                    pvect[isx] = pbvec[isx];
                    next();
                }
            }
        break;
        
        case EXID_RET:
            isx = isxsav;
            execv = executelist;
            pvect = exparamlist;
            pbvec = parambackup;
        break;
        
        case EXID_GET_CONACK:
            prepare2wait((uint8_t *)mqtt_connack, 4);
        break;
        case EXID_GET_PUBACK:
            prepare2wait((uint8_t *)mqtt_puback, 4);
        break;
        case EXID_DATA_DISCON:
            rilSendData((uint8_t *)mqtt_disconnect, MQTT_DISCONN_LEN-9, MQTT_DISCONN_LEN);
        break;
  
        case EXID_CALL_REMOTE_CMD:
            isxsav = isx + 1;
            isx = 0;
            execv = execsublst2;
            pvect = subparalst2;
            pbvec = subpbackup2;
        break;

        case EXID_TRUE_JPF:
            if(iterator){
                --iterator;
                dojmp();
            }else{
                iterator = REMOTE_CHECK_FREQ_DIV;
                next();
            }
        break;
        case EXID_TEST:
//            GPIO_WriteReverse(LED_GPIO_PORT, (GPIO_Pin_TypeDef)LED_GPIO_PINS);

            //byte2decs(sms_current_idx, &highchar, &lowchar);
            send2consoleb(0x0D);
            send2consoleb(0x0A);
            //send2consoleb(highchar);
            //send2consoleb(lowchar);
            //send2consoleb('#');
            //byte2decs(sms_max_mumber, &highchar, &lowchar);
/*            byte2decs(sms_unread, &highchar, &lowchar);
            send2consoleb(highchar);
            send2consoleb(lowchar);
            send2consoleb('#');
            send2console(sms_content,SMS_TXT_BUF_LIMIT);
            send2consoleb(0x0D);
            send2consoleb(0x0A);
*/
            /*
            send2consoleb('@');
            byte2decs(FLASH_ReadByte((uint32_t)&SyncPeriod),&highchar, &lowchar);
            send2consoleb(highchar);
            send2consoleb(lowchar);
            send2consoleb('@');
            byte2decs(exparamlist[0],&highchar, &lowchar);
            send2consoleb(highchar);
            send2consoleb(lowchar);
            send2consoleb(0x0D);
            send2consoleb(0x0A);
            */
            send2consoleb('@');
            send2console((uint8_t*)&at_qiopen[10],31);
            send2consoleb('@');
            send2consoleb(0x0D);
            send2consoleb(0x0A);
            next();
        break;
        
        case ATID_QCFG:
            rilExecute((uint8_t *)at_qcfg, QCFG_LEN-4, QCFG_LEN);
        break;
        case ATID_CPMS:
            echostore = echostore1;
            datcnt = 0;
            
            dptr = cpmsresult;
            datmax = 7;
            dstart = 0;
            rilExecute((uint8_t *)at_cpms, CPMS_LEN-8, CPMS_LEN);
        break;
        case EXID_SMSIDX_EQSKIP:
            dptr = cpmsresult;  //+CPMS: 19,50,19,50,19,50
            //get sms_current_idx
            while(',' != *dptr){
                ++dptr;
            }
            hdcmp = dptr;
            --hdcmp;++dptr;
            sms_current_idx = *hdcmp-- - 0x30;
            if((*hdcmp >= 0x30)&&(*hdcmp <= 0x39)){
                sms_current_idx += 10*(*hdcmp - 0x30);
            }
            //get sms_max_mumber
            while(',' != *dptr){
                ++dptr;
            }
            --dptr;
            sms_max_mumber = *dptr-- - 0x30;
            sms_max_mumber += 10*(*dptr - 0x30);
            
            if(sms_processed_idx == sms_current_idx){
                dojmp();
            }else{
                sms_processed_idx = sms_current_idx;
                next();
            }
        break;
        case ATID_CMGF:
            rilExecute((uint8_t *)at_cmgf, CMGF_LEN-4, CMGF_LEN);
        break;
        case ATID_CSDH:
            rilExecute((uint8_t *)at_csdh, CSDH_LEN-4, CSDH_LEN);
        break;
        case ATID_CSCS:
            rilExecute((uint8_t *)at_cscs, CSCS_LEN-4, CSCS_LEN);
        break;
        case ATID_CMGR:
            echostore = echostore2;
            eof = 0;
            meta = FALSE;
            meta_type = 1;
            meta_sms_step=0;
            ctnt = FALSE;
            
            datcnt = 0;
            dptr = sms_content;
            datmax = SMS_TXT_BUF_LIMIT;
            //dstart = 0;
            rilExecIndexRead(sms_current_idx, 8, (uint8_t *)at_cmgr, CMGR_LEN-8, CMGR_LEN);
        break;
        case EXID_PARSE:
            if(sms_unread){
                sms_unread = 0;
                
                /*parse vendor id*/
                dptr = sms_content;
                if(next_token()){goto exit_parse;}
                if(VENDOR_ID_B == *hdcmp){
                    --hdcmp;
                    if(VENDOR_ID_F == *hdcmp){
                        //FLASH_SetProgrammingTime(FLASH_PROGRAMTIME_STANDARD);
                        FLASH->CR1 &= (uint8_t)(~FLASH_CR1_FIX);
                        FLASH->CR1 |= (uint8_t)FLASH_PROGRAMTIME_STANDARD;
                        /*vendor id ok, then parse uri(up report interval)*/
                        if(next_token()){goto exit_parse;}
                        if(isDecChar(*hdcmp)){
                            datcnt = *hdcmp-- - 0x30;
                            if(isDecChar(*hdcmp)){
                                datcnt += 10*(*hdcmp - 0x30);
                            }
                            if(datcnt){
                                SyncPeriodSet(datcnt);
                                pgon = TRUE;
                                //FLASH_Unlock(FLASH_MEMTYPE_PROG);
                                FLASH->PUKR = FLASH_RASS_KEY1;
                                FLASH->PUKR = FLASH_RASS_KEY2;
                                //FLASH_ProgramByte(((uint32_t)&SyncPeriod), datcnt);
                                *(PointerAttr uint8_t*) (MemoryAddressCast)(&SyncPeriod) = datcnt;
                            }
                        }
                        /*datcnt = *hdcmp--;
                        if((datcnt>=0x30)&&(datcnt<=0x39)){
                            datcnt -= 0x30;
                            dstart = *hdcmp;
                            if((dstart>=0x30)&&(dstart<=0x39)){
                                dstart -= 0x30;
                                SyncPeriodSet(dstart*10+datcnt);
                            }
                        }*/
                        
                        /*parse socket IP*/
                        if(next_token()){goto exit_parse;}
                        if(0 == reapipv4(hdcmp)){
                            //GPIO_WriteReverse(LED_GPIO_PORT, (GPIO_Pin_TypeDef)LED_GPIO_PINS);
/*send2consoleb(0x0D);
send2consoleb(0x0A);
send2consoleb('<');
send2console(ips0,3);
send2console(ips1,3);
send2console(ips2,3);
send2console(ips3,3);
send2consoleb('>');
send2consoleb(0x0D);
send2consoleb(0x0A);*/
                            if(FALSE == pgon){
                                pgon = TRUE;
                                //FLASH_Unlock(FLASH_MEMTYPE_PROG);
                                FLASH->PUKR = FLASH_RASS_KEY1;
                                FLASH->PUKR = FLASH_RASS_KEY2;
                            }
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&IPS0L) = ips0[0];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&IPS0M) = ips0[1];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&IPS0R) = ips0[2];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&IPS1L) = ips1[0];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&IPS1M) = ips1[1];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&IPS1R) = ips1[2];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&IPS2L) = ips2[0];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&IPS2M) = ips2[1];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&IPS2R) = ips2[2];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&IPS3L) = ips3[0];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&IPS3M) = ips3[1];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&IPS3R) = ips3[2];
                        }
                        /*parse socket PORT*/
                        if(next_token()){goto exit_parse;}
                        if(0 == reaport(hdcmp)){
                            if(FALSE == pgon){
                                pgon = TRUE;
                                //FLASH_Unlock(FLASH_MEMTYPE_PROG);
                                FLASH->PUKR = FLASH_RASS_KEY1;
                                FLASH->PUKR = FLASH_RASS_KEY2;
                            }
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&PORT3) = iport[3];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&PORT2) = iport[2];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&PORT1) = iport[1];
                            *(PointerAttr uint8_t*) (MemoryAddressCast)(&PORT0) = iport[0];
                        }
                        /*parse end, relock flash*/
                        if(pgon){
                            //FLASH_Lock(FLASH_MEMTYPE_PROG);
                            FLASH->IAPSR &= (uint8_t)FLASH_MEMTYPE_PROG;
                            pgon = FALSE;
                        }
                    }
                }
            }
            if(sms_max_mumber == sms_processed_idx){
                rilExecute((uint8_t *)at_cmgd, CMGD_LEN-4, CMGD_LEN); //delete all message
            }
        exit_parse:next();
        break;
        default:next();break;
        }
    }
}

int8_t next_token()
{
    uint8_t mc=0;
    while('&' != *dptr){
        ++dptr;
        if(++mc>40){
            return -1;
        }
    }
    hdcmp = dptr;
    --hdcmp;++dptr;
    return 0;
}

int8_t reapipv4(uint8_t* ipbuf)
{
    uint8_t n,m;
    uint8_t* sx;
    uint8_t ch;
    uint8_t erf;
    m = 4;
    while(m--){
        n = 3;
        erf=FALSE;
        if(3 == m){
            sx = ips3;
        }else if(2 == m){
            sx = ips2;
        }else if(1 == m){
            sx = ips1;
        }else if(0 == m){
            sx = ips0;
        }
        
        while(n){
            --n;
            ch = *ipbuf--;
            if(isDecChar(ch)){
                sx[n] = ch;
            }else{
                erf = TRUE;
                break;
            }
        }
        
        if(2 == n){
            return -1;
        }else if(1 == n){
            sx[0] = 0x30;
            sx[1] = 0x30;
        }else if(0 == n){
            if(erf == TRUE){
                sx[0] = 0x30;
            }else{
                ipbuf--;
            }
        }
    }
    return 0;
}

uint8_t isDecChar(uint8_t ch)
{
    if((ch >= 0x30)&&(ch <= 0x39)){
        return TRUE;
    }
    return FALSE;
}

int8_t reaport(uint8_t* pobuf)
{
    uint8_t n;
    uint8_t ch;
    for(n=0; n<4; n++)
    {
        ch = *pobuf--;
        if(isDecChar(ch)){
            iport[n] = ch;
        }else{
            break;
        }
    }
    if(0 == n){
        return -1;
    }else if(1 == n){
        iport[1] = 0x30;
        iport[2] = 0x30;
        iport[3] = 0x30;
    }else if(2 == n){
        iport[2] = 0x30;
        iport[3] = 0x30;
    }else if(3 == n){
        iport[3] = 0x30;
    }else{
    }
    return 0;
}
